﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.IO;
using System.Collections;

namespace CsvHelper
{
    public class CsvHandler
    {
        //public static DataTable CsvToDataTable(string path, bool hasTitle = true, Dictionary<string, Type> convert = null, char sep=',')
        //{
        //    DataTable dt = new DataTable();
        //    if (convert == null)
        //    {
        //        convert = new Dictionary<string, Type>();
        //    }
        //    using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
        //    {
        //        using (StreamReader sr = new StreamReader(fs, Encoding.Default))
        //        {
        //            string line;
        //            Dictionary<int, string> colmaps = new Dictionary<int, string>();
        //            string[] items = null;
        //            while ((line = sr.ReadLine()) != null)
        //            {
        //                items = line.Split(sep).Select(x=>x.Trim()).ToArray(); //sep分隔符, 去掉分割后字符两边空格
        //                if (hasTitle)
        //                {
        //                    for (int i = 0; i < items.Length; i++)
        //                    {
        //                        if (convert.ContainsKey(items[i]))
        //                        {
        //                            dt.Columns.Add(items[i], convert[items[i]]);
        //                        }
        //                        else
        //                        {
        //                            dt.Columns.Add(items[i], typeof(string)); //默认为string
        //                        }
        //                        colmaps.Add(i, items[i]);
        //                    }
        //                    hasTitle = false;
        //                    continue;
        //                }
        //                DataRow dr = dt.NewRow();
        //                for (int i = 0; i < items.Length; i++)
        //                {
        //                    if (convert.ContainsKey(colmaps[i]))
        //                    {
        //                        dr[i] = Convert.ChangeType(items[i], convert[colmaps[i]]);
        //                    }
        //                    else
        //                    {
        //                        dr[i] = items[i];
        //                    }
        //                }
        //                dt.Rows.Add(dr);

        //            }
        //        }
        //    }
        //    return dt;
        //}

        public static DataTable CsvToDataTable(string path, bool hasTitle = true, Dictionary<string, Type> convert = null, char sep = ',')
        {
            DataTable dt = new DataTable();
            var rows = File.ReadAllLines(path, Encoding.Default);
            Dictionary<int, string> colmaps = new Dictionary<int, string>();
            string[] items = rows[0].Split(sep).Select(x => x.Trim()).ToArray();
            if (hasTitle)
            {
                for (int i = 0; i < items.Length; i++)
                {
                    if (convert != null && convert.ContainsKey(items[i]))
                    {
                        dt.Columns.Add(items[i], convert[items[i]]);
                    }
                    else
                    {
                        dt.Columns.Add(items[i], typeof(string)); //默认为string
                    }
                    colmaps.Add(i, items[i]);
                }
            }
            else // 没有titile，默认从0开始添加数字title
            {
                for (int i = 0; i < items.Length; i++)
                {
                    dt.Columns.Add(i.ToString(), typeof(string));
                    colmaps.Add(i, i.ToString());
                }
            }
            for (int k = 0; k < rows.Length; k++)
            {
                if (hasTitle && k == 0) continue;
                DataRow dr = dt.NewRow();
                items = rows[k].Split(sep).Select(x => x.Trim()).ToArray();
                for (int i = 0; i < items.Length; i++)
                {
                    if (convert != null && convert.ContainsKey(colmaps[i]))
                    {
                        if(items[i] == "")
                        {
                            dr[i] = Activator.CreateInstance(convert[colmaps[i]]);
                        }
                        else
                        {
                            dr[i] = Convert.ChangeType(items[i], convert[colmaps[i]]);
                        }
                    }
                    else
                    {
                        dr[i] = items[i];
                    }
                }
                dt.Rows.Add(dr);
            }
            return dt;
        }
            

        public static void DataTableToCsv(DataTable dt, string path, char sep = ',')
        {
            StringBuilder sb = new StringBuilder();
            IEnumerable<string> colNames = dt.Columns.Cast<DataColumn>().Select(col => col.ColumnName);
            sb.AppendLine(string.Join(sep.ToString(), colNames));
            foreach (DataRow row in dt.Rows)
            {
                IEnumerable<string> fields = row.ItemArray.Select(x => x.ToString());
                sb.AppendLine(string.Join(sep.ToString(), fields));
            }
            File.WriteAllText(path, sb.ToString());           
        }


        public static List<string> CSVToList(string path, bool hasTitle = true)
        {
            List<string> dt = new List<string>();
            StreamReader sr = new StreamReader(path, Encoding.Default);
            string line;
            //string[] items = null;
            while ((line = sr.ReadLine()) != null)
            {
                //items = line.Split(',');
                dt.Add(line);
            }
            sr.Close();
            return dt;
        }
      

        private static string ToUpper(string str)
        {
            return str.Substring(0, 1).ToUpper() + str.Substring(1);
        }

        //public static string GetTitleLine(Type t, string sep, string supName = null)
        //{
        //    string line = null;
        //    string value;
        //    foreach (var fd in t.GetFields())
        //    {
        //        object[] objAttrs = fd.GetCustomAttributes(typeof(NonSaveToCsvAttribute), false);
        //        if (objAttrs.Length > 0)
        //        {
        //            continue;
        //        }

        //        if (fd.FieldType.IsValueType || fd.FieldType == typeof(string)) // 值类型或者string
        //        {
        //            if (supName == null)
        //            {
        //                value = fd.Name; // 首字母不大写
        //            }
        //            else
        //            {
        //                value = supName + ToUpper(fd.Name);
        //            }
        //        }
        //        else if (fd.FieldType is IEnumerable)
        //        {
        //            value = fd.FieldType.Name;
        //        }
        //        else //引用类型
        //        {
        //            if (supName == null)
        //            {
        //                value = GetTitleLine(fd.FieldType, sep, fd.Name);
        //            }
        //            else
        //            {
        //                value = GetTitleLine(fd.FieldType, sep, supName + ToUpper(fd.Name));
        //            }
        //        }
        //        line += sep + value;
        //    }
        //    return line.Substring(1); //去掉最前面的sep
        //}

        public static string GetTitleLine<T>(T data, string sep, string supName = null)
        {
            string line = "";
            string value = "";
            foreach (var fd in data.GetType().GetFields())
            {
                object[] objAttrs = fd.GetCustomAttributes(typeof(NonSaveToCsvAttribute), false);
                if (objAttrs.Length > 0)
                {
                    continue;
                }
                if (fd.FieldType.IsValueType || fd.FieldType == typeof(string)) // 值类型或者string
                {
                    value = supName == null ? fd.Name : supName + ToUpper(fd.Name);
                }
                else if (fd.GetValue(data) is ICollection) // list 类型
                {
                    int count = ((ICollection)fd.GetValue(data)).Count;
                    value = "";
                    for(int i=0; i<count; i++)
                    {
                        value += supName == null ? sep + fd.Name + i.ToString() : sep + supName + ToUpper(fd.Name)+i.ToString();
                    }
                    value = value.Substring(1);
                }
                else if (fd.GetValue(data) is Array) // array 类型
                {
                    int count = ((Array)fd.GetValue(data)).Length;
                    value = "";
                    for (int i = 0; i < count; i++)
                    {
                        value += supName == null ? sep + fd.Name + i.ToString() : sep + supName + ToUpper(fd.Name) + i.ToString();
                    }
                    value = value.Substring(1);
                }
                else //引用类型
                {
                    var obj = fd.GetValue(data);
                    if(obj == null)
                    {
                        obj = Activator.CreateInstance(fd.FieldType); 
                    }
                    if (supName == null)
                    {
                        value = GetTitleLine(obj, sep, fd.Name);
                    }
                    else
                    {
                        value = GetTitleLine(obj, sep, supName + ToUpper(fd.Name));
                    }
                }
                line += sep + value;
            }
            return line.Substring(1); //去掉最前面的sep
        }


        public static string GetDataLine<T>(T data, string sep, string timeFormat = "yyyy-MM-dd HH:mm:ss") where T: new()
        {
            var fields = data.GetType().GetFields();
            string line = "";
            string value = "";

            foreach (var fd in fields)
            {

                object[] objAttrs = fd.GetCustomAttributes(typeof(NonSaveToCsvAttribute), false);
                if (objAttrs.Length > 0)
                {
                    continue;
                }
                var obj = fd.GetValue(data);
                if (fd.FieldType == typeof(DateTime))
                {
                    value = ((DateTime)obj).ToString(timeFormat);
                }
                else if (fd.FieldType.IsValueType)
                {
                    value = obj.ToString();
                }
                else if (fd.FieldType == typeof(string))
                {
                    if(obj == null)
                    {
                        value = "";
                    }
                    else
                    {
                        value = obj.ToString();
                    }
                }
                else if(fd.GetValue(data) is ICollection)
                {
                    value = "";
                    foreach(var item in (ICollection)fd.GetValue(data))
                    {
                        value += sep + item.ToString();
                    }
                    value = value.Substring(1);
                }
                else if(fd.GetValue(data) is Array)
                {
                    value = "";
                    foreach(var item in (Array)fd.GetValue(data))
                    {
                        value += sep + item.ToString();
                    }
                    value = value.Substring(1);
                }
                else //引用类型
                {
                    if(obj == null)
                    {
                        obj = Activator.CreateInstance(fd.FieldType);
                    }
                    value =  GetDataLine(obj, sep, timeFormat);
                }
                line += sep + value;
            }
            return line.Substring(1);
        }
        

        public static void ListToCSV<T>(string path, List<T> dataList, string timeFormat = "yyyy-MM-dd HH:mm:ss", string sep=",") where T:new()
        {
            StreamWriter sr = new StreamWriter(path, false, Encoding.Default);
            string title;
            if (dataList.Count == 0)
            {
                title = GetTitleLine(Activator.CreateInstance(typeof(T)), sep);
            }
            else
            {
                title = GetTitleLine(dataList[0], sep);
            }
            sr.WriteLine(title);
            string dataLine;
            foreach(var data in dataList)
            {
                dataLine = GetDataLine(data, sep, timeFormat);
                sr.WriteLine(dataLine);
            }
            sr.Close();
        }
    }


    [AttributeUsage(AttributeTargets.Field, Inherited = false)]
    public class NonSaveToCsvAttribute : Attribute
    {
        public NonSaveToCsvAttribute() { }
    }
}
